/*******************************************************************************
 * Copyright (c) 2006 CEA List.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     CEA List - initial API and implementation
 *******************************************************************************/
package com.cea.papyrus.diagram.activity.helper;

import java.util.ArrayList;

import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.uml2.uml.Action;
import org.eclipse.uml2.uml.ActivityEdge;
import org.eclipse.uml2.uml.ActivityNode;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Pin;

import com.cea.papyrus.core.helper.GraphEdgeHelper;
import com.cea.papyrus.core.helper.NodeHelper;
import com.cea.papyrus.core.utils.Debug;
import com.cea.papyrus.diagraminterchange2.di2.Diagram;
import com.cea.papyrus.diagraminterchange2.di2.DiagramElement;
import com.cea.papyrus.diagraminterchange2.di2.GraphEdge;
import com.cea.papyrus.diagraminterchange2.di2.GraphElement;
import com.cea.papyrus.diagraminterchange2.di2.Uml1SemanticModelBridge;

/**
 * Manages an ActivityEdge
 *
 *
 * @author Gilles Cannenterre
 * @since 26 mars 07
 */
public class EdgeActivityEdgeHelper extends GraphEdgeHelper {

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.common.factories.GraphEdgeFactory#addUMLElement(org.eclipse.uml2.uml.Element, org.eclipse.uml2.uml.Element)
	 */
	@Override
	public boolean addUMLElement(Element element, Element umlParent) {
		if (umlParent instanceof Pin) {
			return ((Action)((Pin)umlParent).getOwner()).getActivity().getEdges().add((ActivityEdge)element);
		}
		if (umlParent instanceof ActivityNode) {
			return ((ActivityNode)umlParent).getActivity().getEdges().add((ActivityEdge)element);
		}
		return false;
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.common.factories.GraphEdgeFactory#canCreateGraphElement(com.cea.papyrus.core.diagraminterchange2.di2.GraphElement)
	 */
	@Override
	public boolean canCreateGraphElement(GraphElement source){
		Debug.debug(this,"canCreateGraphElement(GraphElement)", channel);
		if (source instanceof Diagram ){
			return true;
		}
		if (source.getSemanticModel()!=null ){
			if (((Uml1SemanticModelBridge)source.getSemanticModel()).getElement()!=null){
				Element eltSource=((Uml1SemanticModelBridge)source.getSemanticModel()).getElement();			
				return canCreateUMLElement(eltSource);
			}
		}
		return false;
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.common.factories.GraphEdgeFactory#createGraphEdge(org.eclipse.uml2.uml.Element, com.cea.papyrus.core.diagraminterchange2.di2.Diagram)
	 */
	@Override
	public ArrayList<DiagramElement> createGraphEdge(Element umlElement, Diagram diagram){
		Debug.debug(this,"createGraphEdge(Element,Diagram)", channel);
		GraphEdge ge=(GraphEdge)this.createGraphElement(umlElement, null, null, null);
		//look for UML connected UML element
		if (!(umlElement instanceof ActivityEdge)){
			Debug.error(this, "EdgeActivityEdgeHelper.createGraphEdge: "+ umlElement+ "is not an ActivityEdge!", channel);
		}

		ActivityEdge ae = (ActivityEdge)umlElement;
		Element umltarget = ae.getTarget();
		Element umlsource = ae.getSource();
		super.endCreateGraphElement(umlsource, umltarget, ge, diagram);
		return new ArrayList<DiagramElement> ();
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.common.factories.GraphEdgeFactory#removeUMLElement(org.eclipse.uml2.uml.Element, org.eclipse.uml2.uml.Element)
	 */
	@Override
	public boolean removeUMLElement(Element element, Element umlParent) {
		if (umlParent instanceof Pin) {
			return ((Action)((Pin)umlParent).getOwner()).getActivity().getEdges().add((ActivityEdge)element);
		}
		if (umlParent instanceof ActivityNode) {
			return ((ActivityNode)umlParent).getActivity().getEdges().remove(element);
		}
		return false;
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.common.factories.GraphEdgeFactory#createGraphElement(org.eclipse.uml2.uml.Element, com.cea.papyrus.core.diagraminterchange2.di2.GraphElement, org.eclipse.draw2d.geometry.Point, org.eclipse.draw2d.geometry.Dimension)
	 */
	@Override
	public GraphElement createGraphElement(Element umlChild, GraphElement parent, Point location, Dimension size) {
		GraphElement graphElement=super.createGraphElement(umlChild, null, location, size);
		NodeHelper nf=new NodeHelper();
		// Name of the activityedge
		GraphElement graphNode=nf.createGraphElement(null, graphElement, new Point(0, 10), null);
		graphNode.setFontSize(9);
		graphNode.setIsVisible(false);

		// Stereotype of the activityedge
		graphNode=nf.createGraphElement(null, graphElement, new Point(0, 30), null);
		graphNode.setFontSize(9);

		// Guard of the activityedge
		graphNode=nf.createGraphElement(null, graphElement, new Point(0, 25), null);
		graphNode.setFontSize(9);
		graphNode.setIsVisible(false);

		// Weight of the activityedge
		graphNode=nf.createGraphElement(null, graphElement, new Point(0, 20), null);
		graphNode.setFontSize(9);
		graphNode.setIsVisible(false);

		// The parent has to be connected in last, because a event will be triggered.
		if(parent!=null){
			parent.getContained().add(graphElement);
		}

		return graphElement;	
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.common.helper.GraphEdgeHelper#connect(org.eclipse.uml2.uml.Element, org.eclipse.uml2.uml.Element, org.eclipse.uml2.uml.Element)
	 */
	@Override
	public boolean connect(Element source, Element target, Element link) {
		ActivityNode activityNode = null;
		if (source instanceof Pin) {	
			activityNode = (ActivityNode)((Action)((Pin)source).getOwner());
		} else if (target instanceof Pin) {
			activityNode = (ActivityNode)((Action)((Pin)target).getOwner());
		} else {
			activityNode = (ActivityNode)source;
		}	
		((ActivityEdge)link).setName(getBaseString()+((ActivityNode)source).getName()+"_"+((ActivityNode)target).getName());
		((ActivityEdge)link).setSource((ActivityNode)source);
		((ActivityEdge)link).setTarget((ActivityNode)target);
		activityNode.getActivity().getEdges().add(((ActivityEdge)link));
		return true;
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.common.helper.GraphEdgeHelper#deconnect(org.eclipse.uml2.uml.Element, org.eclipse.uml2.uml.Element, org.eclipse.uml2.uml.Element)
	 */
	@Override
	public boolean deconnect(Element source, Element target, Element link) {
		Debug.debug(this,"deconnect(Element,Element,Element)", channel);
		((ActivityEdge)link).setTarget(null);
		((ActivityEdge)link).setSource(null);
		return true;
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.common.helper.NodeHelper#getNewUMLElementName(org.eclipse.uml2.uml.Element)
	 */
	@Override
	public String getNewUMLElementName(Element umlParent) {
		String name = ""; //$NON-NLS-1$

		// i <10000: avoid infinite loops
		for(int i=0; i< 10001; i++ ) {
			name = getBaseString()+i;
			if (umlParent instanceof Pin) {
				if (null == ((Action)((Pin)umlParent).getOwner()).getActivity().getEdge(name)) {
					return name;
				}
			} else {
				if (null == ((ActivityNode)umlParent).getActivity().getEdge(name)) {
					return name;
				}
			}		
		}
		return getBaseString()+"X"; //$NON-NLS-1$
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.common.factories.GraphEdgeFactory#canConnect(org.eclipse.uml2.uml.Element, org.eclipse.uml2.uml.Element)
	 */
	@Override
	public boolean canConnect(Element source,Element target){
		if ( canCreateUMLElement(source) && (target ==null ) ) {
			return true;
		}
		if ( (source != target) && 
				(canCreateUMLElement(source) && canCreateUMLElement(target)) ) {
			if (((ActivityNode)source).getActivity() == ((ActivityNode)target).getActivity()) {
				return true;
			}
			if ( (source instanceof Pin) && !(target instanceof Pin) ) {
				if ( ((Action)((Pin)source).getOwner()).getActivity() == ((ActivityNode)target).getActivity()) {
					return true;
				}
			}
			if ( !(source instanceof Pin) && (target instanceof Pin) ) {
				if ( ((Action)((Pin)target).getOwner()).getActivity() == ((ActivityNode)source).getActivity()) {
					return true;
				}
			}
			if ( (source instanceof Pin) && (target instanceof Pin) ) {
				if ( ((Action)((Pin)source).getOwner()).getActivity() == ((Action)((Pin)target).getOwner()).getActivity()) {
					return true;
				}
			}
		}
		return false;
	}

}
